// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

// 包含必要的头文件
#include "AbilitySystemInterface.h"           // 能力系统接口
#include "GameplayCueInterface.h"             // 游戏提示接口
#include "GameplayTagAssetInterface.h"        // 游戏标签资产接口
#include "ModularCharacter.h"                 // 模块化角色基类
#include "Teams/LyraTeamAgentInterface.h"     // Lyra团队代理接口

#include "LyraCharacter.generated.h"          // 生成的头文件

// 前向声明类
class AActor;
class AController;
class ALyraPlayerController;
class ALyraPlayerState;
class FLifetimeProperty;
class IRepChangedPropertyTracker;
class UAbilitySystemComponent;
class UInputComponent;
class ULyraAbilitySystemComponent;
class ULyraCameraComponent;
class ULyraHealthComponent;
class ULyraPawnExtensionComponent;
class UObject;
struct FFrame;
struct FGameplayTag;
struct FGameplayTagContainer;

/**
 * FLyraReplicatedAcceleration: 加速度的压缩表示
 */
USTRUCT()
struct FLyraReplicatedAcceleration
{
    GENERATED_BODY()

    UPROPERTY()
    uint8 AccelXYRadians = 0;    // XY加速度分量的方向，量化表示[0, 2*pi]

    UPROPERTY()
    uint8 AccelXYMagnitude = 0;  // XY分量的加速度率，量化表示[0, MaxAcceleration]

    UPROPERTY()
    int8 AccelZ = 0;             // 原始Z加速度率分量，量化表示[-MaxAcceleration, MaxAcceleration]
};

/** 用于发送快速共享移动更新的类型 */
USTRUCT()
struct FSharedRepMovement
{
    GENERATED_BODY()

    FSharedRepMovement();

    bool FillForCharacter(ACharacter* Character);                    // 为角色填充数据
    bool Equals(const FSharedRepMovement& Other, ACharacter* Character) const;  // 比较是否相等

    bool NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess);  // 网络序列化

    UPROPERTY(Transient)
    FRepMovement RepMovement;        // 复制移动数据

    UPROPERTY(Transient)
    float RepTimeStamp = 0.0f;       // 复制时间戳

    UPROPERTY(Transient)
    uint8 RepMovementMode = 0;       // 复制移动模式

    UPROPERTY(Transient)
    bool bProxyIsJumpForceApplied = false;  // 代理是否应用跳跃力

    UPROPERTY(Transient)
    bool bIsCrouched = false;        // 是否蹲下
};

// 为FSharedRepMovement结构启用网络序列化特性
template<>
struct TStructOpsTypeTraits<FSharedRepMovement> : public TStructOpsTypeTraitsBase2<FSharedRepMovement>
{
    enum
    {
        WithNetSerializer = true,        // 启用网络序列化器
        WithNetSharedSerialization = true, // 启用网络共享序列化
    };
};

/**
 * ALyraCharacter
 *
 *  本项目使用的基础角色Pawn类。
 *  负责向Pawn组件发送事件。
 *  新行为应尽可能通过Pawn组件添加。
 */
UCLASS(Config = Game, Meta = (ShortTooltip = "本项目使用的基础角色Pawn类。"))
class LYRAGAME_API ALyraCharacter : public AModularCharacter, 
                                    public IAbilitySystemInterface, 
                                    public IGameplayCueInterface, 
                                    public IGameplayTagAssetInterface, 
                                    public ILyraTeamAgentInterface
{
    GENERATED_BODY()

public:
    // 构造函数
    ALyraCharacter(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());

    // 获取Lyra玩家控制器
    UFUNCTION(BlueprintCallable, Category = "Lyra|Character")
    ALyraPlayerController* GetLyraPlayerController() const;

    // 获取Lyra玩家状态
    UFUNCTION(BlueprintCallable, Category = "Lyra|Character")
    ALyraPlayerState* GetLyraPlayerState() const;

    // 获取Lyra能力系统组件
    UFUNCTION(BlueprintCallable, Category = "Lyra|Character")
    ULyraAbilitySystemComponent* GetLyraAbilitySystemComponent() const;
    virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;

    // 游戏标签接口实现
    virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override;
    virtual bool HasMatchingGameplayTag(FGameplayTag TagToCheck) const override;
    virtual bool HasAllMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const override;
    virtual bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const override;

    // 切换蹲下状态
    void ToggleCrouch();

    //~AActor接口
    virtual void PreInitializeComponents() override;  // 预初始化组件
    virtual void BeginPlay() override;                // 开始游戏
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;  // 结束游戏
    virtual void Reset() override;                    // 重置
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;  // 获取生命周期复制属性
    virtual void PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker) override;  // 预复制
    //~End of AActor接口

    //~APawn接口
    virtual void NotifyControllerChanged() override;  // 通知控制器改变
    //~End of APawn接口

    //~ILyraTeamAgentInterface接口
    virtual void SetGenericTeamId(const FGenericTeamId& NewTeamID) override;  // 设置通用团队ID
    virtual FGenericTeamId GetGenericTeamId() const override;                 // 获取通用团队ID
    virtual FOnLyraTeamIndexChangedDelegate* GetOnTeamIndexChangedDelegate() override;  // 获取团队改变委托
    //~End of ILyraTeamAgentInterface接口

    /** 在跳过默认属性复制的帧上调用的RPC。这会向所有人复制单个移动更新。 */
    UFUNCTION(NetMulticast, unreliable)
    void FastSharedReplication(const FSharedRepMovement& SharedRepMovement);

    // 上次发送的FSharedRepMovement，避免重复发送
    FSharedRepMovement LastSharedReplication;

    // 更新共享复制
    virtual bool UpdateSharedReplication();

protected:
    // 能力系统初始化和反初始化
    virtual void OnAbilitySystemInitialized();
    virtual void OnAbilitySystemUninitialized();

    // 被控制器拥有和取消拥有
    virtual void PossessedBy(AController* NewController) override;
    virtual void UnPossessed() override;

    // 复制属性回调
    virtual void OnRep_Controller() override;
    virtual void OnRep_PlayerState() override;

    // 设置玩家输入组件
    virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;

    // 初始化游戏标签
    void InitializeGameplayTags();

    // 掉落出世界
    virtual void FellOutOfWorld(const class UDamageType& dmgType) override;

    // 开始死亡序列
    UFUNCTION()
    virtual void OnDeathStarted(AActor* OwningActor);

    // 结束死亡序列
    UFUNCTION()
    virtual void OnDeathFinished(AActor* OwningActor);

    // 禁用移动和碰撞
    void DisableMovementAndCollision();
    
    // 因死亡而销毁
    void DestroyDueToDeath();
    
    // 反初始化和销毁
    void UninitAndDestroy();

    // 角色死亡序列完成时调用
    UFUNCTION(BlueprintImplementableEvent, meta=(DisplayName="OnDeathFinished"))
    void K2_OnDeathFinished();

    // 移动模式改变
    virtual void OnMovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode) override;
    
    // 设置移动模式标签
    void SetMovementModeTag(EMovementMode MovementMode, uint8 CustomMovementMode, bool bTagEnabled);

    // 开始和结束蹲下
    virtual void OnStartCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust) override;
    virtual void OnEndCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust) override;

    // 检查是否可以跳跃
    virtual bool CanJumpInternal_Implementation() const;

private:
    // Pawn扩展组件
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Lyra|Character", Meta = (AllowPrivateAccess = "true"))
    TObjectPtr<ULyraPawnExtensionComponent> PawnExtComponent;

    // 生命值组件
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Lyra|Character", Meta = (AllowPrivateAccess = "true"))
    TObjectPtr<ULyraHealthComponent> HealthComponent;

    // 相机组件
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Lyra|Character", Meta = (AllowPrivateAccess = "true"))
    TObjectPtr<ULyraCameraComponent> CameraComponent;

    // 复制的加速度
    UPROPERTY(Transient, ReplicatedUsing = OnRep_ReplicatedAcceleration)
    FLyraReplicatedAcceleration ReplicatedAcceleration;

    // 团队ID
    UPROPERTY(ReplicatedUsing = OnRep_MyTeamID)
    FGenericTeamId MyTeamID;

    // 团队改变委托
    UPROPERTY()
    FOnLyraTeamIndexChangedDelegate OnTeamChangedDelegate;

protected:
    // 确定拥有结束后新的团队ID
    virtual FGenericTeamId DetermineNewTeamAfterPossessionEnds(FGenericTeamId OldTeamID) const
    {
        // 可以更改为返回OldTeamID以保持分配，或返回某个中立派系的ID等
        return FGenericTeamId::NoTeam;
    }

private:
    // 控制器改变团队回调
    UFUNCTION()
    void OnControllerChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam);

    // 复制加速度回调
    UFUNCTION()
    void OnRep_ReplicatedAcceleration();

    // 复制团队ID回调
    UFUNCTION()
    void OnRep_MyTeamID(FGenericTeamId OldTeamID);
};
